#ifndef ___fat32_procesar_mensajes

#define ___fat32_procesar_mensajes 1

#include "mtlib.c"
#include "f32_acon.c"
#include "f32_fsbs.c"
#include "f32_ltr.c"
#include "f32_mrep.c"
#include "f32_base.c"
#include "f32_cch.c"
#include "f32_psec.c"

int fat32_procesar_mensajes(void);

void fat32_procesar_info_archivo(unsigned int, unsigned int);
void fat32_procesar_crear_archivo(unsigned int, unsigned int);
void fat32_procesar_abrir_archivo(unsigned int, unsigned int);
void fat32_procesar_leer_archivo(unsigned int, unsigned int);
void fat32_procesar_escribir_archivo(unsigned int, unsigned int);
void fat32_insertar_nueva_escritura_pendiente(unsigned int, unsigned long long, unsigned long);
void fat32_procesar_datos_escribir_archivo(unsigned int, unsigned int);
void fat32_procesar_fin_datos_escribir(unsigned int, unsigned int);
void fat32_procesar_cerrar_archivo(unsigned int, unsigned int);
void fat32_procesar_truncar_archivo(unsigned int, unsigned int);
void fat32_procesar_crear_directorio(unsigned int, unsigned int);
void fat32_procesar_eliminar_directorio(unsigned int, unsigned int);
void fat32_procesar_renombrar_archivo(unsigned int, unsigned int);
void fat32_procesar_obtener_atributos(unsigned int, unsigned int);
void fat32_procesar_obtener_datos_directorio(unsigned int, unsigned int);
void fat32_procesar_borrar_archivo(unsigned int, unsigned int);
void fat32_procesar_datos_sector(unsigned int, unsigned int);
void fat32_procesar_escribio_sector(unsigned int, unsigned int);

int fat32_procesar_mensajes (void) {
  int tareas = 15;
  if (!mtf_recibir_mensajes(fat32_centro_mensajes)) return tareas;
  mti_mensaje mensaje = mtf_siguiente_mensaje(fat32_centro_mensajes);
  switch (mensaje.categoria) {
  case MTA_ACEPTAR: // solo se da cuando entra una nueva conexion del FUSE
  case MTA_HANDSHAKE: // no se da
    break;
  case MTA_CERRAR:
    if (mtf_conexion_es_interna(fat32_centro_mensajes, mensaje.remitente)) break; // conexion del FUSE
    if (mensaje.remitente == fat32_conexion_consola) break;
    fat32_cerrar_conexion(mensaje.remitente);
    if (!fat32_conexiones_existentes()) tareas = 255;
    break;
  case MTA_MENSAJE:
    switch (mensaje.tipo) {
    case MTR_NULL:
    case MTQ_MENSAJE_NO_VALIDO:
    case MTR_NO_LEYO_SECTOR:
    case MTR_NO_ESCRIBIO_SECTOR:
      break;
    case MTE_NULL:
      mtf_enviar_mensaje(fat32_centro_mensajes, mensaje.remitente, MTR_NULL);
      break;
    case MTE_OBTENER_INFO_FS:
      mtf_enviar_mensaje(fat32_centro_mensajes, mensaje.remitente, MTR_INFO_FS, (int) 512, (int) (512 * bootsector.sectoresPorCluster),
                                                                                               (int) (512 * bootsector.sectoresporFAT));
      break;
    case MTE_OBTENER_INFO_ARCHIVO:
      fat32_procesar_info_archivo(mensaje.remitente, mensaje.codigo);
      break;
    case MTE_CREAR_ARCHIVO:
      fat32_procesar_crear_archivo(mensaje.remitente, mensaje.codigo);
      break;
    case MTE_ABRIR_ARCHIVO:
      fat32_procesar_abrir_archivo(mensaje.remitente, mensaje.codigo);
      break;
    case MTE_LEER_ARCHIVO:
      fat32_procesar_leer_archivo(mensaje.remitente, mensaje.codigo);
      break;
    case MTE_ESCRIBIR_ARCHIVO:
      tareas = 0;
      fat32_procesar_escribir_archivo(mensaje.remitente, mensaje.codigo);
      break;
    case MTE_DATOS_ESCRIBIR_ARCH:
      tareas = 0;
      fat32_procesar_datos_escribir_archivo(mensaje.remitente, mensaje.codigo);
      break;
    case MTE_FIN_DATOS_ESCRIBIR:
      fat32_procesar_fin_datos_escribir(mensaje.remitente, mensaje.codigo);
      break;
    case MTQ_ESCRIBIR_DATOS_CACHE:
      fat32_invalidar_cache();
      break;
    case MTQ_CERRAR_ARCHIVO:
      fat32_procesar_cerrar_archivo(mensaje.remitente, mensaje.codigo);
      break;
    case MTE_TRUNCAR_ARCHIVO:
      fat32_procesar_truncar_archivo(mensaje.remitente, mensaje.codigo);
      break;
    case MTE_CREAR_DIRECTORIO:
      fat32_procesar_crear_directorio(mensaje.remitente, mensaje.codigo);
      break;
    case MTE_ELIMINAR_DIRECTORIO:
      fat32_procesar_eliminar_directorio(mensaje.remitente, mensaje.codigo);
      break;
    case MTE_RENOMBRAR_ARCHIVO:
      fat32_procesar_renombrar_archivo(mensaje.remitente, mensaje.codigo);
      break;
    case MTE_OBTENER_ATRIBUTOS:
      fat32_procesar_obtener_atributos(mensaje.remitente, mensaje.codigo);
      break;
    case MTE_OBTENER_DATOS_DIR:
      fat32_procesar_obtener_datos_directorio(mensaje.remitente, mensaje.codigo);
      break;
    case MTE_BORRAR_ARCHIVO:
      fat32_procesar_borrar_archivo(mensaje.remitente, mensaje.codigo);
      break;
    case MTQ_ESCRIBIR_TODO_CACHE:
      fat32_invalidar_cache();
      break;
    case MTR_DATOS_SECTOR:
      fat32_procesar_datos_sector(mensaje.remitente, mensaje.codigo);
      break;
    case MTR_ESCRIBIO_SECTOR:
      fat32_procesar_escribio_sector(mensaje.remitente, mensaje.codigo);
      break;
    default:
      mtf_enviar_mensaje(fat32_centro_mensajes, mensaje.remitente, MTQ_MENSAJE_NO_VALIDO);
    }
  }
  mtf_descartar_mensaje(fat32_centro_mensajes, mensaje.codigo);
  return tareas;
}

void fat32_procesar_info_archivo (unsigned int solicitante, unsigned int codigoMensaje) {
  char * nombreArchivo = NULL;
  mtf_obtener_datos(fat32_centro_mensajes, codigoMensaje, (char **) &nombreArchivo);
  fat32tr_informacion_archivo(nombreArchivo, remitente);
  free(nombreArchivo);
}

void fat32_procesar_crear_archivo (unsigned int solicitante, unsigned int codigoMensaje) {
  char * nombreArchivo = NULL;
  short permisos;
  mtf_obtener_datos(fat32_centro_mensajes, codigoMensaje, (char **) &nombreArchivo, (short *) &permisos);
  fat32_transaccion_de_manejo_de_entradas(FAT32_CREAR_ARCHIVO, solicitante, nombreArchivo, &permisos);
  free(nombreArchivo);
}

void fat32_procesar_abrir_archivo (unsigned int solicitante, unsigned int codigoMensaje) {
  char * nombreArchivo = NULL;
  char modo;
  mtf_obtener_datos(fat32_centro_mensajes, codigoMensaje, (char **) &nombreArchivo, (char *) &modo);
  fat32_transaccion_de_manejo_de_archivos(FAT32_ABRIR_ARCHIVO, solicitante, modo, 0, 0, nombreArchivo);
  free(nombreArchivo);
}

void fat32_procesar_leer_archivo (unsigned int solicitante, unsigned int codigoMensaje) {
  long long descriptor;
  long inicio, cantidad;
  mtf_obtener_datos(fat32_centro_mensajes, codigoMensaje, (long long *) &descriptor, (long *) &inicio, (long *) &cantidad);
  fat32_transaccion_de_manejo_de_archivos(FAT32_LEER_ARCHIVO, solicitante, descriptor, inicio, cantidad, NULL);
}

void fat32_procesar_escribir_archivo (unsigned int solicitante, unsigned int codigoMensaje) {
  long long descriptor;
  long inicio;
  mtf_obtener_datos(fat32_centro_mensajes, codigoMensaje, (long long *) &descriptor, (long *) &inicio, NULL, NULL);
  fat32_insertar_nueva_escritura_pendiente(solicitante, descriptor, inicio);
  mtf_enviar_mensaje(fat32_centro_mensajes, solicitante, MTR_PUEDE_ESCRIBIR_ARCH, descriptor);
}

void fat32_insertar_nueva_escritura_pendiente (unsigned int remitente, unsigned long long descriptor, unsigned long posInicio) {
  unsigned int posicion;
  for (posicion = 0; posicion < fat32_escrituras.cantEscrituras; posicion ++)
    if ((fat32_escrituras.escrituras[posicion].remitente == remitente) && (fat32_escrituras.escrituras[posicion].descriptor == descriptor))
      break;
  if (posicion == fat32_escrituras.cantEscrituras) {
    fat32_escrituras.cantEscrituras ++;
    fat32_escrituras.escrituras = fb_cambiar_tamano(fat32_escrituras.escrituras, sizeof(fat32_escrituras_recibidas),
                                                                                    fat32_escrituras.cantEscrituras);
  } else
    if (fat32_escrituras.escrituras[posicion].datos) free(fat32_escrituras.escrituras[posicion].datos);
  fat32_escrituras.escrituras[posicion].remitente = remitente;
  fat32_escrituras.escrituras[posicion].descriptor = descriptor;
  fat32_escrituras.escrituras[posicion].datos = NULL;
  fat32_escrituras.escrituras[posicion].cantidad = 0;
  fat32_escrituras.escrituras[posicion].posicionInicio = posInicio;
}

void fat32_procesar_datos_escribir_archivo (unsigned int solicitante, unsigned int codigoMensaje) {
  long long descriptor;
  unsigned short cantidadDatos;
  long numParte;
  void * datos = NULL;
  mtf_obtener_datos(fat32_centro_mensajes, codigoMensaje, (long long *) &descriptor, (long *) &numParte, (unsigned short *) &cantidadDatos,
                                                                                                                          (void **) &datos);
  unsigned int posicion;
  for (posicion = 0; posicion < fat32_escrituras.cantEscrituras; posicion ++)
    if ((fat32_escrituras.escrituras[posicion].remitente == solicitante) && (fat32_escrituras.escrituras[posicion].descriptor == descriptor))
      break;
  if (posicion == fat32_escrituras.cantEscrituras) {
    free(datos);
    return;
  }
  unsigned long c;
  c = fat32_escrituras.escrituras[posicion].cantidad;
  fat32_escrituras.escrituras[posicion].cantidad += cantidadDatos;
  fat32_escrituras.escrituras[posicion].datos = fb_cambiar_tamano(fat32_escrituras.escrituras[posicion].datos, 1,
                                                                  fat32_escrituras.escrituras[posicion].cantidad);
  memcpy(((char *) (fat32_escrituras.escrituras[posicion].datos)) + c, datos, cantidadDatos);
  free(datos);
  mtf_enviar_mensaje(fat32_centro_mensajes, solicitante, MTR_RECIBIO_DATOS_ARCH, descriptor, numParte);
}

void fat32_procesar_fin_datos_escribir (unsigned int solicitante, unsigned int codigoMensaje) {
  long long descriptor;
  mtf_obtener_datos(fat32_centro_mensajes, codigoMensaje, (long long *) &descriptor);
  unsigned int posicion;
  for (posicion = 0; posicion < fat32_escrituras.cantEscrituras; posicion ++)
    if ((fat32_escrituras.escrituras[posicion].remitente == solicitante) && (fat32_escrituras.escrituras[posicion].descriptor == descriptor))
      break;
  if (posicion == fat32_escrituras.cantEscrituras) return;
  fat32_transaccion_de_manejo_de_archivos(FAT32_ESCRIBIR_ARCHIVO, solicitante, descriptor,
                                          fat32_escrituras.escrituras[posicion].posicionInicio,
                                          fat32_escrituras.escrituras[posicion].cantidad, fat32_escrituras.escrituras[posicion].datos);
  free(fat32_escrituras.escrituras[posicion].datos);
  fat32_escrituras.cantEscrituras --;
  fat32_escrituras.escrituras[posicion] = fat32_escrituras.escrituras[fat32_escrituras.cantEscrituras];
  fat32_escrituras.escrituras = fb_cambiar_tamano(fat32_escrituras.escrituras, sizeof (fat32_escrituras_recibidas),
                                                                                   fat32_escrituras.cantEscrituras);
}

void fat32_procesar_cerrar_archivo (unsigned int solicitante, unsigned int codigoMensaje) {
  long long descriptor;
  mtf_obtener_datos(fat32_centro_mensajes, codigoMensaje, (long long *) &descriptor);
  fat32_transaccion_de_manejo_de_archivos(FAT32_CERRAR_ARCHIVO, solicitante, descriptor, 0, 0, NULL);
}

void fat32_procesar_truncar_archivo (unsigned int solicitante, unsigned int codigoMensaje) {
  char * nombre = NULL;
  long posicion;
  mtf_obtener_datos(fat32_centro_mensajes, codigoMensaje, (char **) &nombre, (long *) &posicion);
  fat32_transaccion_de_manejo_de_entradas(FAT32_TRUNCAR_ARCHIVO, solicitante, nombre, &posicion);
  free(nombre);
}

void fat32_procesar_crear_directorio (unsigned int solicitante, unsigned int codigoMensaje) {
  char * nombre = NULL;
  mtf_obtener_datos(fat32_centro_mensajes, codigoMensaje, (char **) &nombre, NULL);
  fat32_transaccion_de_manejo_de_entradas(FAT32_CREAR_DIRECTORIO, solicitante, nombre, NULL);
  free(nombre);
}

void fat32_procesar_eliminar_directorio (unsigned int solicitante, unsigned int codigoMensaje) {
  char * nombre = NULL;
  mtf_obtener_datos(fat32_centro_mensajes, codigoMensaje, (char **) &nombre);
  fat32_transaccion_de_manejo_de_entradas(FAT32_BORRAR_DIRECTORIO, solicitante, nombre, NULL);
  free(nombre);
}

void fat32_procesar_renombrar_archivo (unsigned int solicitante, unsigned int codigoMensaje) {
  char * nombre1 = NULL;
  char * nombre2 = NULL;
  mtf_obtener_datos(fat32_centro_mensajes, codigoMensaje, (char **) &nombre1, (char **) &nombre2);
  fat32_transaccion_de_manejo_de_entradas(FAT32_CAMBIAR_NOMBRE, solicitante, nombre1, nombre2);
  free(nombre1);
  free(nombre2);
}

void fat32_procesar_obtener_atributos (unsigned int solicitante, unsigned int codigoMensaje) {
  char * nombre = NULL;
  mtf_obtener_datos(fat32_centro_mensajes, codigoMensaje, (char **) &nombre);
  fat32_transaccion_de_manejo_de_entradas(FAT32_OBTENER_ATRIBUTOS, solicitante, nombre, NULL);
  free(nombre);
}

void fat32_procesar_obtener_datos_directorio (unsigned int solicitante, unsigned int codigoMensaje) {
  char * nombre = NULL;
  mtf_obtener_datos(fat32_centro_mensajes, codigoMensaje, (char **) &nombre);
  fat32_transaccion_de_manejo_de_entradas(FAT32_LISTAR_DIRECTORIO, solicitante, nombre, NULL);
  free(nombre);
}

void fat32_procesar_borrar_archivo (unsigned int solicitante, unsigned int codigoMensaje) {
  char * nombre = NULL;
  mtf_obtener_datos(fat32_centro_mensajes, codigoMensaje, (char **) &nombre);
  fat32_transaccion_de_manejo_de_entradas(FAT32_BORRAR_ARCHIVO, solicitante, nombre, NULL);
  free(nombre);
}

void fat32_procesar_datos_sector (unsigned int solicitante, unsigned int codigoMensaje) {
  char datos[512];
  void * auxDatos = datos;
  long numSector;
  mtf_obtener_datos(fat32_centro_mensajes, codigoMensaje, (long *) &numSector, (void **) &datos);
  fat32_procesar_datos_sector_entrantes(numSector, datos);
}

void fat32_procesar_escribio_sector (unsigned int solicitante, unsigned int codigoMensaje) {
  long numSector;
  mtf_obtener_datos(fat32_centro_mensajes, codigoMensaje, (long *) &numSector);
  fat32_procesar_escritura_sector_entrante(numSector);
}

#endif